#include <valarray>
#include <sstream>
#include <iomanip>
#include <fstream>
#include "zadacha.h"
#include "is_eq.h"
#include "table.h"
#include "build_upr.h"


//функция подсчета управления и вывода его в файл (в первой колонке -- время, во второй -- управление)
void build_upr (std::vector<std::string> file_w, std::string upr_traject, unsigned tip_upr, input& data) {
    for (unsigned k=0; k<file_w.size(); k++) {
        std::string upravl = (upr_traject+file_w[k]);
        std::ofstream tr(upravl.c_str(), std::ios::trunc);
        unsigned num_upr = data.num_upr;
        std::valarray<double> c(num_upr);
        c = data.c;

        std::vector<unsigned> sum(num_upr+1);
        sum[0]=0;
        double t0=data.t;
        double tf=data.tf;
        unsigned n = data.n;

        std::fstream f_in(file_w[k].c_str()); 
        std::string str, tmp;
        while (getline(f_in,tmp,'\n')) {
            if (!tmp.empty()) str = tmp;
        }
        f_in.close();

        n += data.sum_c;

        std::valarray<double> w(n);
        std::stringstream read_w(str);
        for (unsigned i=0; i<n; i++) read_w >> w[i];

        std::valarray<std::valarray<double> > tau;
        tau.resize(num_upr);                                      //tau --- двумерный вектор векторов: по строкам -- номера управлений, по столбцам -- время
        for (unsigned i=0; i<num_upr; i++) tau[i].resize(c[i]+2); //tau хранит моменты переключения в виде: "t0 моменты переключения tf" для каждого управления
        tau = table(w, data);

        double upr=0;
        const unsigned p=2;
        switch (tip_upr) {
            case 1:                                          //для кусочно-постоянного управления
                  for (unsigned i=1; i<num_upr+1; i++) {
                      sum[i] = (c[i-1]+1)+sum[i-1];
                  }
                  for (double u_ind=0; u_ind<num_upr; u_ind++) {
                      for (double t=t0; (t<tf)||IsEq(t,tf,1e-11); t+=0.001) {
                          tr << std::setiosflags(std::ios::right) << std::setprecision(10)
                             << std::setiosflags(std::ios::fixed | std::ios::showpoint)
                             << std::setw(15) << std::setiosflags(std::ios::right) << t;
                          for (unsigned i=0; i<c[u_ind]+1; i++) {
                              if (((t>tau[u_ind][i])||IsEq(t,tau[u_ind][i],1e-11)) && ((t<tau[u_ind][i+1])||IsEq(t,tau[u_ind][i+1],1e-11))) {
                                  if ((IsEq(t,tau[u_ind][i+1],1e-11)) && (not(IsEq(t,tau[u_ind][c[u_ind]+1],1e-11)))) {
                                      upr=w[i+sum[u_ind]];
                                      tr << std::setw(15) << std::setiosflags(std::ios::right) << upr;
                                      tr << std::endl;
                                      tr << std::setiosflags(std::ios::right) << std::setprecision(10)
                                         << std::setiosflags(std::ios::fixed | std::ios::showpoint)
                                         << std::setw(15) << std::setiosflags(std::ios::right) << t;
                                  }
                                  upr=w[i+sum[u_ind]];
                              }
                          }
                          tr << std::setw(15) << std::setiosflags(std::ios::right) << upr;
                          tr << std::endl;
                      }
                      tr << std::endl << std::endl;
                  }
                  tr.close();
                  break;
            case 2:                                          //для кусочно-линейного непрерывного управления
                  for (unsigned i=1; i<num_upr+1; i++) {
                      sum[i] = (c[i-1]+2)+sum[i-1];
                  }
                  for (double u_ind=0; u_ind<num_upr; u_ind++) {
                      for (double t=t0; (t<tf)||IsEq(t,tf,1e-11); t+=0.001) {
                          tr << std::setiosflags(std::ios::right) << std::setprecision(10)
                             << std::setiosflags(std::ios::fixed | std::ios::showpoint)
                             << std::setw(15) << std::setiosflags(std::ios::right) << t;
                          for (unsigned i=0; i<c[u_ind]+1; i++) {
                              if (((t>tau[u_ind][i])||IsEq(t,tau[u_ind][i],1e-11)) && ((t<tau[u_ind][i+1])||IsEq(t,tau[u_ind][i+1],1e-11))) {
                                  upr=(((w[i+1+sum[u_ind]]-w[i+sum[u_ind]])*t-(tau[u_ind][i]*w[i+1+sum[u_ind]]-tau[u_ind][i+1]*w[i+sum[u_ind]]))/(tau[u_ind][i+1]-tau[u_ind][i]));
                              }
                          }
                          tr << std::setw(15) << std::setiosflags(std::ios::right) << upr;
                          tr << std::endl;
                      }
                      tr << std::endl << std::endl;
                  }
                  tr.close();
                  break;
            case 3:                                          //для кусочно-линейного разрывного управления
                  for (unsigned i=1; i<num_upr+1; i++) {
                      sum[i] = (c[i-1]+1)+sum[i-1];
                  }
                  for (double u_ind=0; u_ind<num_upr; u_ind++) {
                      for (double t=t0; (t<tf)||IsEq(t,tf,1e-11); t+=0.001) {
                          tr << std::setiosflags(std::ios::right) << std::setprecision(10)
                             << std::setiosflags(std::ios::fixed | std::ios::showpoint)
                             << std::setw(15) << std::setiosflags(std::ios::right) << t;
                          for (unsigned j=0,i=0; (j<c[u_ind]+1) && (i<n); j++,i+=p) {
                              if (((t>tau[u_ind][j])||IsEq(t,tau[u_ind][j],1e-11)) && ((t<tau[u_ind][j+1])||IsEq(t,tau[u_ind][j+1],1e-11))) {
                                  if ((IsEq(t,tau[u_ind][j+1],1e-11)) && (not(IsEq(t,tau[u_ind][c[u_ind]+1],1e-11)))) {
                                      upr=(((w[i+1+2*sum[u_ind]]-w[i+2*sum[u_ind]])*t-(tau[u_ind][j]*w[i+1+2*sum[u_ind]]-tau[u_ind][j+1]*w[i+2*sum[u_ind]]))/(tau[u_ind][j+1]-tau[u_ind][j]));
                                      tr << std::setw(15) << std::setiosflags(std::ios::right) << upr;
                                      tr << std::endl;
                                      tr << std::setiosflags(std::ios::right) << std::setprecision(10)
                                         << std::setiosflags(std::ios::fixed | std::ios::showpoint)
                                         << std::setw(15) << std::setiosflags(std::ios::right) << t;
                                  }
                                  upr=(((w[i+1+2*sum[u_ind]]-w[i+2*sum[u_ind]])*t-(tau[u_ind][j]*w[i+1+2*sum[u_ind]]-tau[u_ind][j+1]*w[i+2*sum[u_ind]]))/(tau[u_ind][j+1]-tau[u_ind][j]));
                              }
                          }
                          tr << std::setw(15) << std::setiosflags(std::ios::right) << upr;
                          tr << std::endl;
                      }
                      tr << std::endl << std::endl;
                  }
                  tr.close();
                  break;
        }
    }
}
